﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;


namespace Benchmark_System {
    class BenchmarkSystem {

        /// <summary>
        /// Fields
        /// </summary>
        internal Scheduler scheduler = null;
        internal LoggerTextFile logText = null;
        internal LoggerConsole logConsole = null;
        internal LoggerDB logDB = null;
        internal List<Job> RunningJobs = new List<Job>();
        private readonly object _locker = new object();

        /// <summary>
        /// Constructor
        /// </summary>
        public BenchmarkSystem(string file) {
            scheduler = new Scheduler();
            logText = new LoggerTextFile(file);
            logConsole = new LoggerConsole();
            logDB = new LoggerDB();
            logText.Subscribe(this);
            logConsole.Subscribe(this);
            logDB.Subscribe(this);
        }

        /// <summary>
        /// Method to return the status of the system
        /// Status is all running and queued jobs
        /// </summary>
        /// <returns></returns>
        internal List<Job> Status() {
            //Get all the jobs from the short queue
            List<Job> status = new List<Job>(scheduler.ShortQueue);
            //Get all the jobs from the long queue
            status.AddRange(scheduler.LongQueue);
            //Get all the jobs from the very long queue
            status.AddRange(scheduler.VeryLongQueue);
            //Get all running jobs
            return status;

        }

        /// <summary>
        /// Method to add job to the system
        /// </summary>
        /// <param name="j"></param>
        internal void Submit(Job j, Owner owner) {
            //call the add command on scheduler
            j.owner = owner;
            scheduler.AddJob(j);
            //send the event
            JobSubmitted(this, new JobEvent(j));
        }

        /// <summary>
        /// Method to remove/cancel jobs form the system
        /// </summary>
        /// <param name="j"></param>
        internal void Cancel(Job j) {
            //Remove the job
            scheduler.RemoveJob(j);
            //Call the event
            JobCancelled(this, new JobEvent(j));
        }

        /// <summary>
        /// Method to execute all jobs
        /// </summary>
        internal void ExecuteAll() {
            Job job = scheduler.PopJob();
            while (job != null) {
                        Job threadJob = job;
                        new Thread(() => Proc(threadJob)).Start();
                        job = scheduler.PopJob();
            }
        }

        private void Proc(Job job) {
                RunningJobs.Add(job);
                job.State = Job.JobState.RUNNING;
                JobRunning(this, new JobEvent(job));
                Console.Write(job.Process(null) + " - ");
                int sleep = (int)job.ExpectedRuntime;
                Thread.Sleep(sleep * 1000);
                Scheduler.CpuUsage = Scheduler.CpuUsage - job.Cpu;
                job.State = Job.JobState.STOPPED;
                Console.WriteLine("freed: " + job.Cpu + " Cpu Power");
        }
        /// <summary>
        /// Event that tells the job is terminated
        /// </summary>
        /// <param name="job"></param>
        internal void Terminated(Job job) {
            JobTerminated(this, new EventArgs());
        }

        /// <summary>
        /// Event that tells the job has failed
        /// </summary>
        /// <param name="job"></param>
        internal void Failed(Job job) {
            JobFailed(this, new EventArgs());
        }

        //Event on Job submission
        public event EventHandler JobSubmitted;

        //Event on Job cancel
        public event EventHandler JobCancelled;

        //Event on Job running
        public event EventHandler JobRunning;

        //Event on job terminatinos
        public event EventHandler JobTerminated;

        //Event on job failed
        public event EventHandler JobFailed;
    }
}
